use bytes::{Buf, BufMut, BytesMut};
use crc32fast::Hasher;
use serde::{Deserialize, Serialize};
use tokio_util::codec::{Decoder, Encoder};

impl AsRef<[u8]> for TcpMessage {
    fn as_ref(&self) -> &[u8] {
        unsafe {
            let ptr = self as *const Self as *const u8;
            std::slice::from_raw_parts(ptr, std::mem::size_of::<Self>())
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TcpMessage {
    pub package_sequence: u8,
    pub equipment_type: u8,
    pub equipment_number: u8,
    pub message_type: u8,
    pub message_length: u8,
    pub message_body: Vec<TcpBody>,
    pub checksum: [u8; 4],
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TcpBody {
    pub data: u8,
}

pub struct MyCodec;

impl Encoder<TcpMessage> for MyCodec {
    type Error = std::io::Error;

    fn encode(&mut self, message: TcpMessage, dst: &mut BytesMut) -> Result<(), Self::Error> {
        dst.put_u16(0x55AA);
        // 将消息字段依次写入字节流
        dst.put_u8(message.package_sequence);
        dst.put_u8(message.equipment_type);
        dst.put_u8(message.equipment_number);
        dst.put_u8(message.message_type);
        dst.put_u8(message.message_length);

        let msg_body = &message.message_body;
        let bytes = msg_body
            .iter()
            .map(|TcpBody { data }| data.to_owned())
            .collect::<Vec<u8>>();
        dst.put_slice(&bytes);
        dst.put_slice(&message.checksum);

        Ok(())
    }
}

impl Decoder for MyCodec {
    type Item = TcpMessage;
    type Error = std::io::Error;

    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
        const HEADER: [u8; 2] = [0x55, 0xAA];

        // Check if src has at least the header size
        if src.is_empty() {
            src.clear();
            return Ok(None);
        }

        // Check if the header is correct
        if src[0..2] != HEADER {
            // Skip bytes until we find a valid header
            if let Some(pos) = src.windows(2).position(|window| window == HEADER) {
                src.advance(pos);
            } else {
                // If no valid header found, clear the buffer
                src.clear();
            }
            return Ok(None);
        }

        // Check if we have enough data for a complete message
        let message_length = src[6] as usize;
        let total_length = 11 + message_length;
        if src.len() < total_length {
            return Ok(None);
        }

        // Extract the message body
        let message_body = src[7..(7 + message_length)].to_vec();

        // Extract other fields
        let package_sequence = src[2];
        let equipment_type = src[3];
        let equipment_number = src[4];
        let message_type = src[5];

        let checksum = [
            src[total_length - 4],
            src[total_length - 3],
            src[total_length - 2],
            src[total_length - 1],
        ]; // 修正为两个字节

        // Calculate CRC32 checksum
        let mut hasher = Hasher::new();

        hasher.update(&src[..total_length - 4]); // 修正为两个字节
        let calculated_checksum = hasher.finalize().to_be_bytes();

        // Verify checksum
        if checksum != calculated_checksum {
            // Clear the buffer and skip incomplete/corrupted message
            src.clear();
            return Ok(None);
        }

        // Remove the consumed bytes from the buffer
        src.advance(total_length);

        // Create and return the message
        let message = TcpMessage {
            package_sequence,
            equipment_type,
            equipment_number,
            message_type,
            message_length: message_length as u8,
            message_body: parse_message_body(message_body),
            checksum,
        };

        Ok(Some(message))
    }
}

fn parse_message_body(message_body: Vec<u8>) -> Vec<TcpBody> {
    message_body
        .iter()
        .map(|byte| TcpBody { data: *byte })
        .collect::<Vec<TcpBody>>()
}
